//// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
//package com.linqingying.gitcode.pullrequest.ui.timeline
//
//import com.intellij.collaboration.async.mapState
//import com.intellij.collaboration.async.nestedDisposable
//import com.intellij.collaboration.ui.*
//import com.intellij.collaboration.ui.codereview.CodeReviewChatItemUIUtil
//import com.intellij.collaboration.ui.codereview.CodeReviewTimelineUIUtil
//import com.intellij.collaboration.ui.codereview.CodeReviewTitleUIUtil
//import com.intellij.collaboration.ui.codereview.comment.CodeReviewCommentTextFieldFactory
//import com.intellij.collaboration.ui.codereview.comment.CodeReviewCommentUIUtil
//import com.intellij.collaboration.ui.codereview.comment.CommentInputActionsComponentFactory
//import com.intellij.collaboration.ui.codereview.comment.submitActionIn
//import com.intellij.collaboration.ui.codereview.list.error.ErrorStatusPanelFactory
//import com.intellij.collaboration.ui.codereview.list.error.ErrorStatusPresenter
//import com.intellij.collaboration.ui.codereview.timeline.comment.CommentTextFieldFactory
//import com.intellij.collaboration.ui.util.bindTextHtmlIn
//import com.intellij.collaboration.ui.util.bindTextIn
//import com.intellij.collaboration.ui.util.bindVisibilityIn
//import com.intellij.collaboration.util.getOrNull
//import com.intellij.ide.DataManager
//import com.intellij.openapi.actionSystem.ActionManager
//import com.intellij.openapi.actionSystem.ActionPlaces
//import com.intellij.openapi.actionSystem.DataProvider
//import com.intellij.openapi.actionSystem.PlatformDataKeys
//import com.intellij.openapi.util.text.HtmlBuilder
//import com.intellij.openapi.util.text.HtmlChunk
//import com.intellij.ui.AnimatedIcon
//import com.intellij.ui.ColorUtil
//import com.intellij.ui.PopupHandler
//import com.intellij.ui.ScrollPaneFactory
//import com.intellij.ui.components.panels.ListLayout
//import com.intellij.ui.components.panels.Wrapper
//import com.intellij.util.ui.JBFont
//import com.intellij.util.ui.JBUI
//import com.intellij.util.ui.UIUtil
//import com.intellij.util.ui.update.UiNotifyConnector
//import kotlinx.coroutines.CoroutineScope
//import kotlinx.coroutines.flow.*
//import com.linqingying.gitcode.exceptions.GitCodeAuthenticationException
//import com.linqingying.gitcode.i18n.GitCodeBundle
//import com.linqingying.gitcode.pullrequest.ui.details.model.GCPRDetailsFull
//import com.linqingying.gitcode.pullrequest.ui.emoji.GCReactionsComponentFactory
//import com.linqingying.gitcode.pullrequest.ui.emoji.GCReactionsPickerComponentFactory
//import com.linqingying.gitcode.ui.component.GCHtmlErrorPanel
//import javax.swing.Action
//import javax.swing.JComponent
//import javax.swing.JLabel
//import javax.swing.JPanel
//import javax.swing.event.ChangeEvent
//import javax.swing.event.ChangeListener
//
//internal class GCPRFileEditorComponentFactory(private val timelineVm: GCPRTimelineViewModel,
//                                              private val initialDetails: GCPRDetailsFull,
//                                              private val cs: CoroutineScope) {
//
//  private val uiDisposable = cs.nestedDisposable()
//
//  fun create(): JComponent {
//    val mainPanel = Wrapper()
//    val loadedDetails = timelineVm.detailsVm.details
//      .map { it.getOrNull() }.filterNotNull().stateIn(cs, SharingStarted.Eagerly, initialDetails)
//
//    val header = createTitle(loadedDetails)
//    val description = createDescription(loadedDetails)
//    val itemComponentFactory = createItemComponentFactory()
//
//    val timeline = ComponentListPanelFactory.createVertical(cs, timelineVm.timelineItems, componentFactory = itemComponentFactory)
//
//    val progressAndErrorPanel = JPanel(ListLayout.vertical(0, ListLayout.Alignment.CENTER)).apply {
//      isOpaque = false
//      val errorPanel = ErrorStatusPanelFactory.create(cs, timelineVm.loadingError, ErrorPresenter())
//
//      val loadingIcon = JLabel(AnimatedIcon.Default()).apply {
//        border = CodeReviewTimelineUIUtil.ITEM_BORDER
//        isVisible = false
//        bindVisibilityIn(cs, timelineVm.isLoading)
//      }
//
//      add(errorPanel)
//      add(loadingIcon)
//    }.let {
//      CollaborationToolsUIUtil
//        .wrapWithLimitedSize(it, CodeReviewChatItemUIUtil.TEXT_CONTENT_WIDTH + CodeReviewTimelineUIUtil.ITEM_HOR_PADDING * 2)
//    }
//
//    val timelinePanel = VerticalListPanel().apply {
//      border = JBUI.Borders.empty(CodeReviewTimelineUIUtil.VERT_PADDING, 0)
//
//      add(header)
//      add(description)
//      add(timeline)
//
//      add(progressAndErrorPanel)
//
//      timelineVm.commentVm?.also {
//        val commentTextField = createCommentField(it).apply {
//          border = JBUI.Borders.empty(CodeReviewChatItemUIUtil.ComponentType.FULL.inputPaddingInsets)
//        }
//        add(commentTextField)
//      }
//    }
//
//    val scrollPane = ScrollPaneFactory.createScrollPane(timelinePanel, true).apply {
//      isOpaque = false
//      viewport.isOpaque = false
//      verticalScrollBar.model.addChangeListener(object : ChangeListener {
//        private var firstScroll = true
//
//        override fun stateChanged(e: ChangeEvent) {
//          if (firstScroll && verticalScrollBar.value > 0) firstScroll = false
//          if (!firstScroll) {
//            timelineVm.requestMore()
//          }
//        }
//      })
//    }
//    UiNotifyConnector.doWhenFirstShown(scrollPane) {
//      timelineVm.requestMore()
//    }
//
//    mainPanel.setContent(scrollPane)
//
//    DataManager.registerDataProvider(mainPanel, DataProvider {
//      when {
//        PlatformDataKeys.UI_DISPOSABLE.`is`(it) -> uiDisposable
//        GCPRTimelineViewModel.DATA_KEY.`is`(it) -> timelineVm
//        else -> null
//      }
//    })
//
//    val actionManager = ActionManager.getInstance()
//    actionManager.getAction("GitCode.PullRequest.Timeline.Update").registerCustomShortcutSet(scrollPane, uiDisposable)
//    val groupId = "GitCode.PullRequest.Timeline.Popup"
//    PopupHandler.installPopupMenu(scrollPane, groupId, ActionPlaces.POPUP)
//
//    return mainPanel
//  }
//
//  private fun createTitle(loadedDetailsState: StateFlow<GCPRDetailsFull>): JComponent {
//    val titlePane = SimpleHtmlPane().apply {
//      font = JBFont.h2().asBold()
//
//      bindTextHtmlIn(cs, loadedDetailsState.map { details ->
//        CodeReviewTitleUIUtil.createTitleText(
//          title = details.titleHtml,
//          reviewNumber = "#${details.id.number}",
//          url = details.url,
//          tooltip = GitCodeBundle.message("open.on.gitcode.action")
//        )
//      })
//    }
//    val header = titlePane.let {
//      CollaborationToolsUIUtil.wrapWithLimitedSize(it, CodeReviewChatItemUIUtil.TEXT_CONTENT_WIDTH)
//    }.apply {
//      border = JBUI.Borders.empty(CodeReviewTimelineUIUtil.HEADER_VERT_PADDING, CodeReviewTimelineUIUtil.ITEM_HOR_PADDING)
//    }
//    return header
//  }
//
//  private fun createDescription(loadedDetailsState: StateFlow<GCPRDetailsFull>): JComponent {
//    val canEdit = loadedDetailsState.value.canEditDescription
//    val canReact = loadedDetailsState.value.canReactDescription
//    val author = loadedDetailsState.value.author
//    val createdAt = loadedDetailsState.value.createdAt
//
//    val textPane = SimpleHtmlPane(customImageLoader = timelineVm.htmlImageLoader).apply {
//      bindTextIn(cs, loadedDetailsState.mapState { it.descriptionHtml ?: noDescriptionHtmlText })
//    }
//
//    val reactionsVm = timelineVm.detailsVm.reactionsVm
//    val contentPane = VerticalListPanel(CodeReviewTimelineUIUtil.VERTICAL_GAP).apply {
//      add(EditableComponentFactory.wrapTextComponent(cs, textPane, timelineVm.detailsVm.descriptionEditVm))
//      add(GCReactionsComponentFactory.create(cs, reactionsVm))
//    }
//    val actionsPanel = HorizontalListPanel(CodeReviewCommentUIUtil.Actions.HORIZONTAL_GAP).apply {
//      if (canEdit) {
//        add(CodeReviewCommentUIUtil.createEditButton {
//          timelineVm.detailsVm.editDescription()
//        })
//      }
//      if (canReact) {
//        add(CodeReviewCommentUIUtil.createAddReactionButton {
//          val parentComponent = it.source as JComponent
//          GCReactionsPickerComponentFactory.showPopup(reactionsVm, parentComponent)
//        })
//      }
//    }
//
//    return GCPRTimelineItemUIUtil.createTimelineItem(timelineVm.avatarIconsProvider, author, createdAt, contentPane, actionsPanel)
//  }
//
//  private fun createCommentField(vm: GCPRNewCommentViewModel): JComponent {
//    val submitShortcutText = CommentInputActionsComponentFactory.submitShortcutText
//    val actions = CommentInputActionsComponentFactory.Config(
//      primaryAction = MutableStateFlow(vm.submitActionIn(cs, GitCodeBundle.message("action.comment.text"), GCPRNewCommentViewModel::submit)),
//      submitHint = MutableStateFlow(GitCodeBundle.message("pull.request.comment.hint", submitShortcutText))
//    )
//    val icon = CommentTextFieldFactory.IconConfig.of(CodeReviewChatItemUIUtil.ComponentType.FULL,
//                                                     timelineVm.avatarIconsProvider, timelineVm.currentUser.avatarUrl)
//
//    return CodeReviewCommentTextFieldFactory.createIn(cs, vm, actions, icon)
//  }
//
//  private fun createItemComponentFactory() = GCPRTimelineItemComponentFactory(timelineVm)
//
//  private val noDescriptionHtmlText by lazy {
//    HtmlBuilder()
//      .append(GitCodeBundle.message("pull.request.timeline.no.description"))
//      .wrapWith(HtmlChunk.font(ColorUtil.toHex(UIUtil.getContextHelpForeground())))
//      .wrapWith("i")
//      .toString()
//  }
//
//  private inner class ErrorPresenter : ErrorStatusPresenter.Text<Throwable> {
//    override fun getErrorTitle(error: Throwable): String = GitCodeBundle.message("pull.request.timeline.cannot.load")
//
//    override fun getErrorDescription(error: Throwable): String =
//      if (error is GitCodeAuthenticationException) GitCodeBundle.message("pull.request.list.error.authorization")
//      else GCHtmlErrorPanel.getLoadingErrorText(error)
//
//    override fun getErrorAction(error: Throwable): Action? = timelineVm.loadingErrorHandler.getActionForError(error)
//  }
//}
